package com.example.zjx8969.myapplication.view

import android.content.Context
import android.graphics.*
import android.graphics.Color
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.example.zjx8969.myapplication.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlin.math.abs
import kotlin.math.min
import kotlin.math.roundToInt

class SuperposedAvatarsView @JvmOverloads constructor(
        context: Context,
        attributeSet: AttributeSet? = null,
        defStyleAttr: Int = 0
) : View(context, attributeSet, defStyleAttr) {
    val scope = SupervisorJob() + Dispatchers.Main
    val paint = Paint().apply {
        isAntiAlias = true
    }
    private val diameter: Float
    private val itemInterval: Int
    private val maxItemCount: Int
    private val bitmapSource: Array<Bitmap?>
    private val rect = RectF()
    private val pressPoint = PointF()
    private val miniDistance = ViewConfiguration.get(context).scaledTouchSlop
    private val hasMoreIcon: Boolean
    private var moreIcon: Bitmap? = null
    private var actualItemCount = 0
    private var itemOnClickLister: ((Int) -> Unit)? = null
    private val right2Left: Boolean
    private var strokePaint: Paint? = null
    private var showAllImagesNoMoreIcon = false//当图片恰好可以放在所有的位置上，不必显示more icon

    init {
        val attributes = context.obtainStyledAttributes(attributeSet, R.styleable.SuperposedAvatarsView)
        val moreIconId = attributes.getResourceId(R.styleable.SuperposedAvatarsView_moreIcon, -1)
        maxItemCount = attributes.getInt(R.styleable.SuperposedAvatarsView_maxItemCount, 0)
        itemInterval = attributes.getDimension(R.styleable.SuperposedAvatarsView_itemIntervals, 6F).roundToInt()
        diameter = attributes.getDimension(R.styleable.SuperposedAvatarsView_imageDiameter, 25f)
        right2Left = attributes.getBoolean(R.styleable.SuperposedAvatarsView_rightToLeft, false)
        val strokeWidth = attributes.getDimension(R.styleable.SuperposedAvatarsView_strokeWidth, 0f)
        val strokeColor = attributes.getColor(R.styleable.SuperposedAvatarsView_strokeColor, Color.WHITE)
        attributes.recycle()
        hasMoreIcon = (-1 != moreIconId)
        if (hasMoreIcon) moreIcon = BitmapFactory.decodeResource(resources, moreIconId)
        bitmapSource = arrayOfNulls(maxItemCount)
        setLayerType(LAYER_TYPE_HARDWARE, null)
        if (strokeWidth > 0) strokePaint = Paint().apply {
            style = Paint.Style.STROKE
            isAntiAlias = true
            color = strokeColor
            this.strokeWidth = strokeWidth
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (actualItemCount == 0) setMeasuredDimension(0, 0) else {
            val measureHeight = when (MeasureSpec.getMode(heightMeasureSpec)) {
                MeasureSpec.EXACTLY -> MeasureSpec.getSize(heightMeasureSpec)
                else -> diameter.toInt()
            }

            setMeasuredDimension((actualItemCount * diameter).toInt() + (actualItemCount - 1) * itemInterval,
                    measureHeight)
        }

    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        val top = (measuredHeight - diameter.toInt()).shr(1).toFloat()
        canvas?.let { canvas1 ->
            if (right2Left) {
                drawFromRightToLeft(top, canvas1)
            } else {
                drawFromLeftToRight(top, canvas1)
            }

        }
    }

    private fun drawFromRightToLeft(top: Float, canvas: Canvas) {
        var right = measuredWidth.toFloat()
        val radius = diameter / 2
        bitmapSource.forEach { bitmap ->
            bitmap?.let { bitmap1 ->
                rect.set(right - diameter, top, right, top + diameter)
                canvas.drawBitmap(bitmap1, null, rect, paint)
                strokePaint?.let {
                    canvas.drawCircle(rect.centerX(), rect.centerY(), radius, it)
                }

            }
            right=rect.left-itemInterval //-= (diameter + itemInterval)
        }
        if (!showAllImagesNoMoreIcon) moreIcon?.let {
            rect.set(right - diameter, top, right, diameter + top)
            canvas.drawBitmap(it, null, rect, paint)
        }
    }

    private fun drawFromLeftToRight(top: Float, canvas: Canvas) {
        var left = 0F
        val radius = diameter / 2
        for (element in bitmapSource) {
            element?.let { bitmap ->
                rect.set(left, top, left + diameter, diameter + top)
                canvas.drawBitmap(bitmap, null, rect, paint)
                strokePaint?.let {
                    canvas.drawCircle(rect.centerX(), rect.centerY(), radius, it)
                }
            }
            left = rect.right + itemInterval
        }

        if (!showAllImagesNoMoreIcon) moreIcon?.let {
            rect.set(left, top, left + diameter, diameter + top)
            canvas.drawBitmap(it, null, rect, paint)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                pressPoint.x = event.x
                pressPoint.y = event.y
            }
            MotionEvent.ACTION_UP -> {
                if (abs(event.x - pressPoint.x) < miniDistance
                        && abs(event.y - pressPoint.y) < miniDistance) {
                    val avatarCircle = RectF()
                    var left = 0F
                    val top = (measuredHeight - diameter.toInt()).shr(1).toFloat()
                    for (index in 0 until maxItemCount) {
                        avatarCircle.set(left, top, left + diameter, diameter + top)
                        if (avatarCircle.contains(event.x, event.y)) {
                            itemOnClickLister?.invoke(index)
                            break
                        }
                        left += diameter + itemInterval
                    }
                }
            }
        }
        return true//super.onTouchEvent(event)

    }

    fun setOnClickListener(listener: (Int) -> Unit) {
        itemOnClickLister = listener
    }

    fun setAvatarUrls(vararg urls: String) {
        val availableSize = if (hasMoreIcon && urls.size > maxItemCount) maxItemCount - 1 else maxItemCount
        showAllImagesNoMoreIcon = (hasMoreIcon && urls.size == maxItemCount)
        val size = min(availableSize, urls.size)
        if (size != actualItemCount) {
            actualItemCount = min(maxItemCount, urls.size)
            requestLayout()
        }
        urls.forEachIndexed { index, s ->
            if (index < size) Glide.with(this).asBitmap().load(s)
                    .transform(RoundedCorners(diameter.roundToInt().shr(1)))
                    .addListener(object : RequestListener<Bitmap> {
                        override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                            bitmapSource[index] = resource
                            postInvalidate()
                            return true
                        }

                        override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean = true
                    }).preload(diameter.toInt(), diameter.toInt())
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        bitmapSource.forEachIndexed { index, it ->
            it?.recycle()
            bitmapSource[index] = null
        }
        scope.cancelChildren()
    }
}